package com.hk.core.service.elasticsearch.reactive.impl;

import co.elastic.clients.elasticsearch.core.search.FieldSuggester;
import com.hk.commons.query.Order;
import com.hk.commons.query.QueryModel;
import com.hk.commons.query.SortUtils;
import com.hk.commons.query.page.QueryPage;
import com.hk.commons.util.AssertUtils;
import com.hk.core.elasticsearch.query.Condition;
import com.hk.core.elasticsearch.repository.BaseReactiveElasticsearchRepository;
import com.hk.core.service.elasticsearch.reactive.ReactiveElasticService;
import org.springframework.data.domain.Persistable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.function.UnaryOperator;

/**
 * @author Kevin
 * @date 2022-7-23 17:31
 */
public abstract class ReactiveElasticSearchServiceImpl<T extends Persistable<ID>, ID extends Serializable>
        implements ReactiveElasticService<T, ID> {

    protected abstract BaseReactiveElasticsearchRepository<T, ID> getBaseReactiveElasticsearchRepository();

    @Override
    public Mono<QueryPage<T>> queryForPage(QueryModel<T> query) {
        return getBaseReactiveElasticsearchRepository().queryForPage(query);
    }

    @Override
    public Mono<Boolean> exists(T t) {
        return getBaseReactiveElasticsearchRepository().count(t)
                .map(count -> count > 0);
    }

    @Override
    public Mono<Long> count(T t) {
        return getBaseReactiveElasticsearchRepository().count(t);
    }

    @Override
    public Mono<Void> deleteById(ID id) {
        return getBaseReactiveElasticsearchRepository().deleteById(id);
    }

    @Override
    public Mono<Void> deleteAllById(Iterable<ID> ids) {
        return getBaseReactiveElasticsearchRepository().deleteAllById(ids);
    }

    @Override
    public Mono<Void> delete(T entity) {
        return getBaseReactiveElasticsearchRepository().delete(entity);
    }

    @Override
    public Mono<Void> delete(Iterable<T> entities) {
        return getBaseReactiveElasticsearchRepository().deleteAll(entities);
    }

    @Override
    public Mono<T> insert(T t, UnaryOperator<T> operator) {
        return getBaseReactiveElasticsearchRepository().save(operator.apply(t));
    }

    @Override
    public Flux<T> batchInsert(Iterable<T> entities) {
        return getBaseReactiveElasticsearchRepository().saveAll(entities);
    }

    @Override
    public Mono<T> updateById(T t, UnaryOperator<T> operator) {
        T entity = operator.apply(t);
        AssertUtils.isTrue(!entity.isNew(), "更新实体ID 不能为空");
        return getBaseReactiveElasticsearchRepository().save(entity);
    }

    @Override
    public Mono<T> findById(ID id) {
        return getBaseReactiveElasticsearchRepository().findById(id);
    }

    @Override
    public Flux<T> findAll(Order... orders) {
        return getBaseReactiveElasticsearchRepository().findAll(SortUtils.toSort(orders));
    }

    @Override
    public Flux<T> findByIds(Iterable<ID> ids) {
        return getBaseReactiveElasticsearchRepository().findAllById(ids);
    }

    @Override
    public Mono<Boolean> existsById(ID id) {
        return getBaseReactiveElasticsearchRepository().existsById(id);
    }

    @Override
    public Mono<Long> count() {
        return getBaseReactiveElasticsearchRepository().count();
    }

    @Override
    public Mono<Void> bulkUpdate(Collection<T> entities) {
        return getBaseReactiveElasticsearchRepository().bulkUpdate(entities);
    }

    @Override
    public Mono<QueryPage<T>> queryForPage(List<Condition> conditions, int pageIndex, int pageSize, Order... orders) {
        return getBaseReactiveElasticsearchRepository().queryForPage(conditions, pageIndex, pageSize, orders);
    }

    @Override
    public Flux<T> findAll(List<Condition> conditions, Order... orders) {
        return getBaseReactiveElasticsearchRepository().findAll(conditions, orders);
    }

    @Override
    public Flux<String> suggest(FieldSuggester suggester) {
        return getBaseReactiveElasticsearchRepository().suggest(suggester);
    }
}
